/**
 * @Author      : xingnan
 * @Email       : 457415936@qq.com
 * @Time        : 16:51
 * @File        : daemonize_windows.go
 * @Project     : toolbox
 * @Description : GoLand
 */
package com

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
)

func processIsRunning(pid int) error {
	_, err := os.FindProcess(pid)
	if err != nil {
		return err
	}
	return nil
}

// AppExit exit app
func AppExit(name string, pidfile string, force bool) error {
	pid, err := AppIsRunningEx(pidfile)
	if err != nil {
		return fmt.Errorf("%s is not running", name)
	}
	process, err := os.FindProcess(pid)
	if err != nil {
		return fmt.Errorf("%s is not running", name)
	}
	err = process.Kill()
	if err != nil {
		return fmt.Errorf("cannot kill %s", name)
	}
	os.Remove(pidfile)
	return nil
}

// AppDaemonizedEx run
func AppDaemonizedEx(name, pidfile, stderr string) error {
	pid, err := AppIsRunningEx(pidfile)
	if err != nil {
		return fmt.Errorf("%s is running, pid=%d", name, pid)
	}
	ek := strings.ToUpper(name) + "_DAEMONIZED"
	if os.Getenv(ek) != "" {
		return AppImmobilized(pidfile)
	}
	env := os.Environ()
	wd, err := os.Getwd()
	if err != nil {
		wd, _ = filepath.Split(os.Args[0])
	}
	exe, _ := os.Executable()
	sysattrs := syscall.SysProcAttr{HideWindow: true}
	env = append(env, StrCat(ek, "=1"))
	procAttr := &os.ProcAttr{
		Dir: wd,
		Env: env,
		Sys: &sysattrs,
	}
	p, err := os.StartProcess(exe, os.Args, procAttr)
	if err != nil {
		os.Exit(1)
		return err
	}
	fmt.Fprintf(os.Stderr, "New %s[%d] is running\n", name, p.Pid)
	p.Release()
	os.Exit(0)
	return nil
}

// AppRestart restart app
func AppRestart(name string, pidfile string, arg ...string) error {
	pid, err := AppIsRunningEx(pidfile)
	if err != nil {
		return fmt.Errorf("%s is not running", name)
	}
	p, err := os.FindProcess(pid)
	if err != nil {
		return err
	}
	err = p.Kill()
	if err != nil {
		return err
	}
	exe, err := os.Executable()
	if err != nil {
		return err
	}
	var cmd exec.Cmd
	cmd.Path = exe
	cmd.Args = append([]string{exe}, arg...)
	err = cmd.Run()
	if err != nil {
		return err
	}
	return nil
}

// on windows, only call AppRestart
func NewAppRestart(name, pidfile string) error {
	return AppRestart(name, pidfile, "-d")
}
